package text;
/**
 * @author Stanislav Lapitsky
 * @version 1.0
 */

import java.awt.Insets;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;

import javax.swing.JEditorPane;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Element;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyledDocument;
import javax.swing.text.StyledEditorKit;
import javax.swing.text.ViewFactory;
import javax.swing.text.rtf.RTFEditorKit;

public class PageableEditorKit extends RTFEditorKit {

	public static final String PAGE_BREAK_ATTR_NAME="page_break_attribute";
	public static final int DRAW_PAGE_INSET = 15;
	public static final int HF_SHIFT=3;

	private static final long serialVersionUID = 38362024187299814L;

	PageableViewFactory factory = new PageableViewFactory(this);
	DocumentListener relayoutListener = new RelayoutDocumentListener(this);

	protected int pageWidth = 150;
	protected int pageHeight = 200;
	protected Insets pageMargins = new Insets(10, 10, 10, 10);
	protected JEditorPane header;
	protected JEditorPane footer;
	protected boolean isValidHF;
	boolean isPageBreakInsertion = false;

    /**
     * Constructs kit instance
     */
    public PageableEditorKit() {
    }

    /**
     * Sets page width
     * @param width int width value in pixels
     */
    public void setPageWidth(int width) {
        pageWidth = width;
        isValidHF=false;
    }

    /**
     * gets page width
     * @return int width in pixels
     */
    public int getPageWidth() {
        return pageWidth;
    }

    /**
     * Sets page height
     * @param height int height in pixels
     */
    public void setPageHeight(int height) {
        pageHeight = height;
    }

    /**
     * Gets page height
     * @return int height in pixels
     */
    public int getPageHeight() {
        return pageHeight;
    }

    /**
     * Sets page margins (distance between page content and page edge.
     * @param margins Insets margins.
     */
    public void setPageMargins(Insets margins) {
        pageMargins = margins;
        isValidHF=false;
    }

    public void setHeader(JEditorPane header) {
        this.header=header;
        if (header == null) {
        	return;
        }
        header.getDocument().addDocumentListener(relayoutListener);
        isValidHF=false;
    }
    
    public void setFooter(JEditorPane footer) {
        this.footer=footer;
        if (footer == null) {
        	return;
        }
        footer.getDocument().addDocumentListener(relayoutListener);
        isValidHF=false;
    }
    
    public JEditorPane getHeader() {
        return header;
    }
    
    public JEditorPane getFooter() {
        return footer;
    }

    protected void calculateHFSizes() {
        int hfWidth=pageWidth-pageMargins.left-pageMargins.right-2*DRAW_PAGE_INSET;
        int maxHeight=(pageHeight-pageMargins.top-pageMargins.bottom-2*DRAW_PAGE_INSET)/2;

        if (header!=null) {
            header.setSize(hfWidth, pageHeight);
            int hHeight = Math.min(maxHeight, header.getPreferredSize().height);
            header.setSize(hfWidth, hHeight);
        }

        if (footer!=null) {
            footer.setSize(hfWidth, pageHeight);
            int fHeight = Math.min(maxHeight, footer.getPreferredSize().height);
            footer.setSize(hfWidth, fHeight);
        }
    }

    public void validateHF() {
        if (!isValidHF) {
            calculateHFSizes();

            isValidHF=true;
        }
    }
    
    protected JEditorPane createHeader() {
        JEditorPane header=new JEditorPane();
        header.setEditorKit(new StyledEditorKit());
        try {
            header.getDocument().insertString(0, "header", new SimpleAttributeSet());
        }
        catch (BadLocationException ex) {
            //can't happen
        }

        return header;
    }

    protected JEditorPane createFooter() {
        JEditorPane footer=new JEditorPane();
        footer.setEditorKit(new StyledEditorKit());
        try {
            footer.getDocument().insertString(0, "footer", new SimpleAttributeSet());
        }
        catch (BadLocationException ex) {
            //can't happen
        }

        return footer;
    }

    /**
     * Prints pages content
     * @param editor JEditorPane pane with content.
     * @param pp PaginationPrinter Printable implementation.
     */
    protected void print(JEditorPane editor, PaginationPrinter pp) {
        PrinterJob pJob = PrinterJob.getPrinterJob();
        //by default paper is letter
        pJob.setPageable(pp);
        try {
            pJob.print();
        }
        catch (PrinterException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * gets kit view factory.
     * @return ViewFactory
     */
    public ViewFactory getViewFactory() {
        return factory;
    }

    /**
     * inserts page break element in current caret location
     */
    public void insertPageBreak(final JEditorPane editor) {
        int caretPos=editor.getCaretPosition();
        final SimpleAttributeSet breakAttrs=new SimpleAttributeSet();
        breakAttrs.addAttribute(PAGE_BREAK_ATTR_NAME, Boolean.TRUE);
        DefaultStyledDocument doc=(DefaultStyledDocument)editor.getDocument();
        try {
            isPageBreakInsertion=true;
            char ch=doc.getText(caretPos,1).charAt(0);
            if (ch!='\n') {
                doc.insertString(caretPos, "\n", breakAttrs);
                caretPos++;
            }
            else {
                Element par=doc.getParagraphElement(caretPos);
                caretPos=par.getEndOffset()-1;
            }
            final int pos=caretPos;
            ( (StyledDocument) editor.getDocument()).setCharacterAttributes(pos, 1, breakAttrs, false);
            isPageBreakInsertion=false;
        }
        catch (BadLocationException ex) {
            //do nothing
        }
    }

}


